package core.helpers;

import java.io.IOException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.Dimension;
import org.openqa.selenium.Platform;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.firefox.internal.ProfilesIni;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.UnreachableBrowserException;
import org.openqa.selenium.safari.SafariDriver;
import org.testng.TestException;

import core.ApplicationManager;
import core.config.Config;

public class WebDriverHelper extends DriverHelper
{

	/**
	 * Initializes WebDriverHelper
	 * @param p_manager ApplicationManager instance
	 */
	public WebDriverHelper(ApplicationManager p_manager)
	{
		super(p_manager);
	}

	/**
	 * Runs a local web browser
	 * @param p_browserName Browser name
	 * @param p_location Test location
	 */
	public WebDriver runLocalBrowser(String p_browserName, String p_location)
	{
		switch (manager.testModel().getServerType())
		{
			case Config.SERVER_LOCAL:
			{
				switch (manager.testModel().getOS())
				{
					default:
					{
						try
						{
							if (manager.config().SCREENLOGGER)
							{
								manager.screenLogger().init();
							}

							driver = getBrowserInstance(p_browserName, p_location);
							// http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/WebDriver.Timeouts.html
							driver.manage().timeouts().implicitlyWait(Config.WEBDRIVER_WAIT, TimeUnit.SECONDS);
							driver.manage().timeouts().pageLoadTimeout(Config.WEBDRIVER_WAIT, TimeUnit.SECONDS);
							driver.manage().timeouts().setScriptTimeout(Config.WEBDRIVER_WAIT, TimeUnit.SECONDS);
							// Browser tab handler
							manager.browser().windowHandler = manager.wd().driver().getWindowHandle();

							// Maximize a browser window
							manager.wd().driver().manage().window().maximize();
							manager.wd().driver().manage().window().setSize(new Dimension(1366, 768));

							// Proxy authentification
							if (Config.PROXY_AUTH && !manager.testModel().getProxy().equals("def"))
							{
								manager.thread().start();
							}

							// Launch the ScreenLogger
							if (manager.config().SCREENLOGGER)
							{
								manager.screenLogger().start();
							}
							return driver;

						}
						catch (Exception p_ex)
						{
							return null;
						}
					}
					case Config.SERVER_SAUCELABS:
					{
						this.runRemoteBrowser();
						manager.sauceLabsReport += manager.wd().getSessionId();

						manager.log().info("Sauce Labs report: " + manager.sauceLabsReport);
						return driver;
					}
				}
			}
		}

		return null;
	}

	public boolean isBrowserOpen()
	{
		Boolean isOpen = (driver.toString().contains("(null)")) ? false : true;

		if (isOpen)
		{
			try
			{
				driver.getCurrentUrl();
			}
			catch (UnreachableBrowserException p_ex)
			{
				return false;
			}
		}
		return isOpen;
	}

	/**
	 * Runs a remote web browser on SauceLabs
	 * @param p_os OS name
	 * @param p_browser Browser name
	 * @param p_browserVersion Browser version
	 * @param p_proxy Proxy
	 * @param p_jobName Job name
	 */
	@SuppressWarnings("null")
	public void runRemoteBrowser(String p_os, String p_browser, String p_browserVersion, String p_proxy, String p_jobName)
	{
		DesiredCapabilities capabilities = null;

		// Set Browser Version
		if (p_browserVersion.equals("def"))
		{
			if (p_browser.equals(manager.config().BROWSER_FIREFOX))
			{
				capabilities = getCapabilities(p_browserVersion, p_proxy);
				capabilities.setCapability("version", manager.config().BROWSER_FF_VERSION);
				capabilities.setCapability("screen-resolution", manager.config().SCREEN_RESOLUTION_1280x1024);
			}
			else if (p_browser.equals(manager.config().BROWSER_CHROME))
			{
				capabilities = getCapabilities(p_browserVersion, p_proxy);
				capabilities.setCapability("version", manager.config().BROWSER_CH_VERSION);
				capabilities.setCapability("screen-resolution", manager.config().SCREEN_RESOLUTION_1280x1024);
			}
			else if (p_browser.equals(manager.config().BROWSER_IEXPLORER))
			{
				capabilities = getCapabilities(p_browserVersion, p_proxy);
				capabilities.setCapability("version", manager.config().BROWSER_IE_VERSION);
				capabilities.setCapability("screen-resolution", manager.config().SCREEN_RESOLUTION_1280x1024);
			}
			else if (p_browser.equals(manager.config().BROWSER_SAFARI))
			{
				capabilities = getCapabilities(p_browserVersion, p_proxy);
				capabilities.setCapability("version", manager.config().BROWSER_SF_VERSION);
				capabilities.setCapability("screen-resolution", manager.config().SCREEN_RESOLUTION_1024x768);
			}
		}
		else
		{
			capabilities.setCapability("version", p_browserVersion);
		}

		// Set Job name
		capabilities.setCapability("name", p_jobName);

		// Set OS
		if (p_os.equals(manager.config().OS_WIN_7))
		{
			capabilities.setCapability("platform", "Windows 7");
		}
		else if (p_os.equals(manager.config().OS_WIN_8))
		{
			capabilities.setCapability("platform", Platform.WIN8);
		}
		else if (p_os.equals(manager.config().OS_ANDROID))
		{
			capabilities.setCapability("platform", Platform.LINUX);
		}

		try
		{
			driver = new RemoteWebDriver(
					new URL("http://" + manager.testModel().getSaucelabsUsername() + ":" + manager.testModel().getSaucelabsKey()
							+ "@ondemand.saucelabs.com:80/wd/hub"),
					capabilities);
		}
		catch (Exception ex)
		{
			throw new TestException(ex.toString());
		}
	}

	/**
	 * Runs a remote browser on SauceLabs
	 */
	public void runRemoteBrowser()
	{
		runRemoteBrowser(manager.testModel().getOS(),
				manager.testModel().getBrowserName(),
				manager.testModel().getBrowserVersion(),
				manager.testModel().getLocation(),
				manager.testModel().getPlatform() + ":"
						+ manager.testModel().getTestName() + ":"
						+ manager.testModel().getSiteName() + ":"
						+ manager.testModel().getLocation() + ":"
						+ manager.testModel().getBrowserName() + "_"
						+ manager.testModel().getBrowserVersion());
	}

	/**
	 * Get desired capabilities
	 * @param p_browser Browser name
	 * @param p_proxy Browser proxy
	 * @return DesiredCapabilities instance
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getCapabilities(String p_browser, String p_proxy)
	{
		DesiredCapabilities capabilities = null;

		if (p_browser.equals(manager.config().BROWSER_FIREFOX))
		{
			capabilities = getFirefoxOptions(p_proxy, manager.config().BROWSER_FIREFOX_PROFILE);
		}
		else if (p_browser.equals(manager.config().BROWSER_CHROME))
		{
			capabilities = new DesiredCapabilities().chrome();
			capabilities.setBrowserName("Chrome");
		}
		else if (p_browser.equals(manager.config().BROWSER_IEXPLORER))
		{
			capabilities = getIExplorerOptions(p_proxy);
		}
		else if (p_browser.equals(manager.config().BROWSER_SAFARI))
		{
			capabilities = getSafariOptions(p_proxy);
		}

		return capabilities;
	}

	/**
	 * Gets Chrome options
	 * @param p_proxy Browser proxy
	 * @return ChromeOptions instance
	 */
	private ChromeOptions getChromeOptions(String p_proxy)
	{
		ChromeOptions options = new ChromeOptions();
		options.addArguments("--lang=en_US");

		if (isProxy(p_proxy))
		{
			options.addArguments("--proxy-server=" + p_proxy);
		}

		return options;
	}

	/**
	 * Gets Firefox options
	 * @param p_proxy Browser proxy
	 * @param p_firefoxProfile
	 * @return DesiredCapabilities instance
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getFirefoxOptions(String p_proxy, String p_firefoxProfile)
	{

		DesiredCapabilities capabilities = null;
		ProfilesIni allProfiles = new ProfilesIni();
		FirefoxProfile profile;

		if (p_firefoxProfile == null || p_firefoxProfile.isEmpty())
		{
			profile = new FirefoxProfile();
		}
		else
		{
			profile = allProfiles.getProfile(p_firefoxProfile);
		}
		profile.setPreference("intl.accept_languages", "en_US");
		capabilities = new DesiredCapabilities().firefox();
		capabilities.setBrowserName("Firefox");
		capabilities.setCapability(FirefoxDriver.PROFILE, profile);

		try
		{
			Runtime.getRuntime().exec("FOR /F \"tokens=5 delims= \" %P IN ('netstat -a -n -o ^| findstr :" + 7054 + "') DO TaskKill.exe /PID %P /T /F");
			wait(10);
		}
		catch (IOException e)
		{
			//
		}

		if (isProxy(p_proxy))
		{
			setProxyOptions(capabilities, p_proxy);
		}

		return capabilities;
	}

	/**
	 * Gets IExplorer options
	 * @param p_proxy Browser proxy
	 * @return DesiredCapabilities instance
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getIExplorerOptions(String p_proxy)
	{
		DesiredCapabilities capabilities = null;
		capabilities = new DesiredCapabilities().internetExplorer();
		capabilities.setBrowserName("iexplore");

		if (isProxy(p_proxy))
		{
			setProxyOptions(capabilities, p_proxy);
		}

		return capabilities;
	}

	/**
	 * Gets IExplorer options
	 * @param p_proxy Browser proxy
	 * @return DesiredCapabilities instance
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getSafariOptions(String p_proxy)
	{
		DesiredCapabilities capabilities = null;
		capabilities = new DesiredCapabilities().safari();
		capabilities.setBrowserName("Safari");
		return capabilities;
	}

	/**
	 * Gets Android options
	 * @param p_proxy Browser proxy
	 * @return DesiredCapabilities instance
	 */
	@SuppressWarnings("static-access")
	private DesiredCapabilities getAndroidOptions(String p_proxy)
	{
		DesiredCapabilities capabilities = null;
		capabilities = new DesiredCapabilities().android();
		capabilities.setBrowserName("Android");
		return capabilities;
	}

	private void setProxyOptions(DesiredCapabilities p_capabilities, String p_localProxy)
	{
		Proxy proxy = new Proxy();
		proxy.setHttpProxy(p_localProxy).
				setFtpProxy(p_localProxy).
				setSslProxy(p_localProxy);
		p_capabilities.setCapability("proxy", proxy);
	}

	/**
	 * Get instance of web driver
	 * @param p_browser Browser name
	 * @param p_proxy TODO
	 * @return Instance of browser
	 */
	public WebDriver getBrowserInstance(String p_browser, String p_proxy)
	{
		// Get browser instance
		if (p_browser.equals(manager.config().BROWSER_FIREFOX))
		{
			return new FirefoxDriver(getFirefoxOptions(p_proxy, manager.config().BROWSER_FIREFOX_PROFILE));
		}
		else if (p_browser.equals(manager.config().BROWSER_CHROME))
		{
			return new ChromeDriver(getChromeOptions(p_proxy));
		}
		else if (p_browser.equals(manager.config().BROWSER_IEXPLORER))
		{
			return new InternetExplorerDriver(getIExplorerOptions(p_proxy));
		}
		else if (p_browser.equals(manager.config().BROWSER_SAFARI))
		{
			return new SafariDriver(getSafariOptions(p_proxy));
		}
		else
		{
			throw new TestException("Browser is not supported => " + p_browser);
		}
	}
}